package com.huyna.rss.data;

import java.io.IOException;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.DefaultClientConnection;
import org.apache.http.util.EntityUtils;
import org.jsoup.Jsoup;
import org.jsoup.select.Elements;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import com.huyna.rss.model.RssFeed;
import com.huyna.rss.model.RssItem;

public class RssParser {
    private static String TAG_CHANNEL   = "channel";
    private static String TAG_TITLE     = "title";
    private static String TAG_LINK      = "link";
    private static String TAG_DESCRIP   = "description";
    private static String TAG_ITEM      = "item";
    private static String TAG_PUB_DATE  = "pubDate";
    private static String TAG_LANGUAGE  = "language";
    private static String TAG_GUID      = "guid";
    
    public RssParser() {
        
    }
    
    public RssFeed getRssFeed(String url){
        RssFeed rssFeed = null;
        String rssXml = null;
        
        String rssUrl = getRssLinkFromURL(url);
        if(rssUrl != null){
            rssXml = getXmlFromUrl(rssUrl);
            if(rssXml != null){
                try{
                    Document doc = this.getDomElement(rssXml);
                    NodeList nodeList = doc.getElementsByTagName(TAG_CHANNEL);
                    Element e = (Element)nodeList.item(0);
                    
                    //
                    rssFeed = new RssFeed(this.getValue(e, TAG_TITLE)
                            , this.getValue(e, TAG_LINK)
                            , this.getValue(e, TAG_DESCRIP)
                            , this.getValue(e, TAG_LANGUAGE));
                }
                catch(Exception e){
                    e.printStackTrace();
                }
            }
            else{
                //Fail to fetch rss xml
            }
        }
        else{
            //Rss Url not found
        }
        
        return rssFeed;
    }
    
    
    public List<RssItem> getRssItem(String url){
        List<RssItem> rssItems = new ArrayList<RssItem>();
        String rssXml = null;
        
        String rssUrl = getRssLinkFromURL(url);
        if(rssUrl != null){
            rssXml = getXmlFromUrl(rssUrl);
            if(rssXml != null){
                try{
                    Document doc = this.getDomElement(rssXml);
                    NodeList nodeList = doc.getElementsByTagName(TAG_CHANNEL);
                    Element element = (Element)nodeList.item(0);
                    
                    NodeList items = element.getElementsByTagName(TAG_ITEM);
                    for(int i = 0; i< items.getLength(); i++){
                        Element e = (Element)items.item(i);
                        RssItem item = new RssItem(this.getValue(e, TAG_TITLE)
                                , this.getValue(e, TAG_LINK)
                                , this.getValue(e, TAG_PUB_DATE)
                                , this.getValue(e, TAG_DESCRIP)
                                , this.getValue(e, TAG_GUID));
                        rssItems.add(item);
                    }
                }
                catch(Exception e){
                    e.printStackTrace();
                }
            }
            else{
                //Fail to fetch rss xml
            }
        }
        else{
            //Rss Url not found
        }
        
        return rssItems;
    }
    
    public String getRssLinkFromURL(String url){
        String rssLink = null;
        try{
            org.jsoup.nodes.Document doc = Jsoup.connect(url).get();
            Elements elementRss = doc.select("link[type=application/rss+xml]");
            
            if(elementRss.size() > 0){
                rssLink = elementRss.get(0).attr("href").toString();
            }
            else{
                Elements elementAtom = doc.select("link[type=application/atom+xml]");
                if(elementAtom.size() > 0){
                    rssLink = elementAtom.get(0).attr("href").toString();
                }
            }
        }
        catch (IOException e){
            e.printStackTrace();
        }
        
        return rssLink;
    }
    
    public String getXmlFromUrl(String url){
        String xml = null;
        try{
            DefaultHttpClient httpClient = new DefaultHttpClient();
            HttpGet httpGet = new HttpGet(url);
            
            HttpResponse httpResponse = httpClient.execute(httpGet);
            HttpEntity httpEntity = httpResponse.getEntity();
            xml = EntityUtils.toString(httpEntity);
        }
        catch(UnsupportedEncodingException e){
            e.printStackTrace();
        }
        catch(ClientProtocolException e){
            e.printStackTrace();
        }
        catch(IOException e){
            e.printStackTrace();
        }
        return xml;
    }
    
    public Document getDomElement(String xml){
        Document doc = null;
        DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
        
        try{
            DocumentBuilder docBuilder = dbFactory.newDocumentBuilder();
            InputSource is = new InputSource();
            is.setCharacterStream(new StringReader(xml));
            doc = (Document)docBuilder.parse(is);
        }
        catch(ParserConfigurationException e){
            e.printStackTrace();
        }
        catch(SAXException e){
            e.printStackTrace();
        }
        catch(IOException e){
            e.printStackTrace();
        }
        
        return doc;
    }
    
    public final String getElementValue(Node element){
        Node child;
        
        if(element != null){
            if(element.hasChildNodes()){
                for(child = element.getFirstChild(); child != null; 
                        child = element.getNextSibling()){
                    if(child.getNodeType() == Node.TEXT_NODE
                            || child.getNodeType() == Node.CDATA_SECTION_NODE){
                        return child.getNodeValue();
                    }
                }
            }
        }
        
        return "";
    }
    
    public String getValue(Element item, String str){
        NodeList n = item.getElementsByTagName(str);
        return this.getElementValue(n.item(0));
    }
}
